package com.cyh.nio;

//io 阻塞io,面向流
//nio 非阻塞io，面向缓冲器，需要选择器。
//nio 由Channels、Buffers、Selectors组成，还有Pipe和FileLock
//Channel是双向的，传统的流是单向的。Channel包括：FileChannel(文件读写)、DatagramChannel（UDP读写网络数据）、SocketChannel（TCP读写）、ServerSocketChannel（监听新进来的TCP）.
//Buffer有：ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer；
//Selector: Selector运行单线程处理多个Channel.

/**
 * FileChannel 无法直接打开，需要通过InputStream、OutputStream或RandomAccessFile来获取。
 *   FileChannel的position方法既可以获取当前位置，也可以设置位置。如果位置超过文件的大小，会撑大文件导致文件空洞。
 *   size()：返回当前文件的大小
 *   truncate(1024): 截取文件的前1024个字节。
 *   force(): 将通道中尚未写入的数据强制写入磁盘。
 *   transferTo()和transferFrom: 通道直接的数据传输。
 * */

/**
 * Buffer用于和NIO通道进行交互，数据是从通道读入缓冲区，从缓冲区写入到通道中。
 * 缓冲区本质是一块可以写入数据，然后可以从中读取数据的内存。
 *
 * Buffer的使用步骤：
 * 1、写入数据到buffer
 * 2、调用flip()方法切换到读模式
 * 3、从buffer中读取数据
 * 4、调用clear()方法或者compact()方法， clear()清空整个缓冲区，compact()只会清空已读的数据。
 *
 * Buffer中的函数
 * capacity:指固定大小 的容量，一旦达到这个值，需要将其清空，才可以就行写。
 * position: 写数据时：初始值为0， 写一个数据值加1，最大值为capacity-1;
 *           读数据时：表示读数据的当前位置，通过Buffer.flip()切换到读模式时，position会被重置为0；读出一个数据后，position加1
 * limit: 写数据时：limit表示最多可以写入多少个数据，写模式下，limit等于capacity
 *        读数据时：limit表示Buffer里有多少可读数据（not null的数据）， 因此可以读到之前写入的所有数据。（limit就是写模式中的position的值）
 *
 * Buffer包括ByteBuffer,IntBuffer,CharBuffer等等。
 *
 * Buffer写入数据 的两种方法：
 *   1.从Channel写入Buffer: inChannel.read(buf);
 *   2.通过Buffer的put方法写入。
 *
 *  flip()方法： 从写入Buffer数据模式切换到读数据模式。
 *
 *
 *  Buffer读数据的两种方式：
 *    1.从Buffer读取数据到Channel: inChannel.write(buf);
 *    2.使用Buffer的get()方法读数据。
 *
 *
 * rewind()方法： 将position设回0， limit保持不变，表示可以重新读取Buffer中的所有数据。常用于：读了一部分数据后，又从头开始读取。
 *
 * clear()方法或者compact()方法， clear()清空整个缓冲区，compact()只会清空已读的数据。
 *
 * mark()与reset()方法：mark()标记当前position位置， reset()将position重置到标记位置。
 *
 * slice()方法可以创建一个子缓冲区（缓冲区分片）
 *
 * asReadOnlyBuffer() 只读缓冲区。
 *
 * allocateDirect() 直接缓冲区，可以加快I/O的速度。
 *
 * 内存缓冲区I/O映射
 *
 *
 *
 * */


/**
 * Selector 和 Channel的关系
 *   Selector 一般称为选择器， 也可以翻译为 多路复用器， 它是java NIO核心组件中的一个，用于检查一个或多个NIO Channel 的状态是否处于可读、可写。
 *   如此可实现单线程管理多个channels, 也就可以管理多个网络连接。
 *   使用selector的好处在于：使用更少的线程来就可以来处理通道了，相比使用多个线程，避免了线程上下文切换带来的开销。
 *
 *
 *   不是所有的Channel都能被Selector复用，比如FileChannel就不能使用Selector复用，关键看它是否继承SelectableChannel.
 *   除了FileChannel几乎所有的Channel都可以被Selector复用。
 *
 *   多个Channel注册到一个Selector上面。
 *
 *
 *    Channel.register(Selector sel, int ops);
 *    ops:
 *       -可读：SelectionKey.OP_READ
 *       -可写：SelectionKey.OP_WRITE
 *       -连接：SelectionKey.OP_CONNECT
 *       -接收：SelectionKey.OP_ACCEPT
 *    多个选择是：int key = SelectionKey.OP_READ | SelectionKey.OP_WRITE; 可读可写
 *
 *    wakeUp(): 唤醒阻塞的方法
 *    close(): 关闭Selector;
 *
 * */


/**
 * Pipe
 *   Java NIO 管道是2个线程之间的单向数据连接，Pipe有一个source通道和一个sink通道， 数据会写到sink通道， 从source通道读取
 *
 * */

/**
 * FileLock
 *   文件锁在OS中很常见，如果多个进程同时访问、修改同一个文件，很容易因为文件的数据不同步而出现问题。
 *   给一个文件加锁，同一时间，只能有一个进程修改此文件，或者程序都只能读此文件，这就解决了同步问题。
 *
 *   文件锁是进程级别的，不是线程级别的。文件锁可以解决多个进程并发访问、修改同一个文件的问题，但不能解决多线程并发访问、修改同一个文件的问题
 *
 *   使用文件锁时，同一进程内的多个线程，可以同时访问、修改此文件。
 *
 *   文件锁是当前程序所属的JVM实例持有，一旦获取到文件锁，要调用release(),或者关闭对应的FileChannel对象，或者当前JVM退出，才会释放这个锁。
 *
 *   进程对文件不能重复加锁。
 *
 *   分类：
 *      排它锁： 当前进程可以读写此文件， 其他进程不能读写
 *      共享锁： 当前进程只可以读此文件， 其他进程也可读但不能写。
 *
 *    获取文件锁的方法：
 *      1）lock(): 排它锁， 整个文件加锁
 *      2） lock(long position, long size, boolean shared):shared:是否是共享锁， 部分内容加锁
 *      3）tryLock(): 排它锁， 整个文件加锁
 *      4）tryLock(long position, long size, boolean shared): shared：是否是共享锁， 部分内容加锁
 *
 *    lock和tryLock的区别：lock是阻塞的， tryLock是非阻塞的。
 *
 *    isShare(): 是否是共享锁
 *    isValid(): 文件锁是否还有效。
 *
 * */


/**
 * java Path java7中的内容， 表示文件系统中的路径。一个路径可以指向一个文件或一个目录。可以是绝对路径或相对路径。
 * Path与File类类似。
 *
 * Files跟Paths一起使用。
 *   Files.createDirectory(); //创建目录， 目录不存在或者目录的父目录不存在 都会抛异常。
 *   Files.copy() :将文件拷贝到另外一个目录。 目标目录已存在同名文件，或者要复制的文件不存在， 都会抛异常。 第三个参数加上：StandardCopyOption.REPLACE_EXISTING. 表示可覆盖
 *   Files.move() : 移动文件。注解同上
 *   Files.delete(): 删除文件。
 *   Files.walkFileTree(): 遍历文件树功能
 *
 * */

/**
 * AsynchronousFileChannel: 异步的将数据写入文件。 文件必须存在，否则会抛异常
 *
 * */

/**
 *   Charset静态方法：
 *   forName(String charset): 获取charset对象
 *   availableCharsets(): 支持的所有的编码方式
 *   defaultCharset(): 虚拟机默认的编码方式
 *   isSupported(String charset): 是否支持该编码
 *
 *   普通方法：
 *   name(): 获取Charset对象的编码类型
 *   newEncoder(): 获得编码器对象
 *   newDecoder(): 获得解码器对象
 * */
public class Test01 {
}
